package function

import "fmt"

/** 函数定义 */

/*
init 函数
所有包都可以包含一个 init 函数。
init 函数不应该有任何返回值类型和参数，在我们的代码中也不能显式地调用它。
init 函数的形式如下：
*/
func init() {

}

func Test() {

	// 示例1
	//case1()

	// 示例2
	//case2()

	// 用户自定义的函数类型
	//case3()

	// 把函数作为参数，传递给其它函数
	//case4()

	// 在其它函数中返回函数
	//case5()

	// 高级使用
	//HighLeve()

	case6()

}

func case6() {
	a := []int{5, 6, 7, 8, 9}
	r := iMap(a, func(n int) int { return n * 5 })
	fmt.Println(r)
	fmt.Println("头等函数的实际用途示例2 ")
}

func iMap(s []int, f func(int) int) []int {
	var r []int
	for _, v := range s {
		r = append(r, f(v))
	}
	return r
}

// 在其它函数中返回函数
func case5() {
	s := simple2()
	fmt.Println("在其它函数中返回函数 ", s(60, 7))
}

func simple2() func(a, b int) int {
	f := func(a, b int) int {
		return a + b
	}
	return f
}

// 把函数作为参数，传递给其它函数
func case4() {
	f := func(a, b int) int {
		return a + b
	}
	simple(f)
	fmt.Println("把函数作为参数，传递给其它函数 ")
}

func simple(a func(a, b int) int) {
	fmt.Println(a(60, 7))
}

// 用户自定义的函数类型
func case3() {
	var a add = func(a int, b int) int { return a + b }
	s := a(5, 6)
	fmt.Println("用户自定义的函数类型 Sum", s)
}

type add func(a int, b int) int

// 示例2
func case2() {
	a := func() { fmt.Println("hello world first class function") }
	a()
	fmt.Printf("匿名函数： %T", a)
}

// 示例1
func case1() {
	n1 := calculate1(4, 5)
	fmt.Println("计算函数结果：", n1)

	n2 := calculate1(4, 5)
	fmt.Println("计算函数结果：", n2)

	n3 := calculate3(44.5, 3)
	fmt.Println("计算函数结果：", n3)

	area, perimeter := rectProps(10.8, 5.6)
	fmt.Printf("函数多返回值：面积 %.2f 周长 %.2f \n", area, perimeter)

	// 多返回参数，不需要这么多返回值
	area2, _ := rectProps(10.8, 5.6)
	fmt.Printf("多返回参数，不需要这么多返回值：面积 %.2f \n", area2)

	area3, _ := rectProps2(10.8, 5.6)
	fmt.Printf("命名返回值：面积 %.2f \n", area3)

}

/*
Sub 函数用于计算两个整数的差
参数 a 被减数
参数 b 减数
返回值 两数之差
*/
func calculate1(num1 int, num2 int) int {
	return num1 + num2
}

// 当函数参数类型一致可在最后写类型
func calculate2(num1, num2 int) int {
	return num1 + num2
}

// 物品价格 * 购买数据量， 返回购买金额
func calculate3(price float32, num int) float32 {
	return price * float32(num)
}

// 多返回参数，计算并返回矩形面积和周长的函数
func rectProps(length, width float64) (float64, float64) {
	// 计算面积
	var area = length * width
	// 计算周长
	var perimeter = (length + width) * 2
	return area, perimeter
}

// 命名返回值
func rectProps2(length, width float64) (area, perimeter float64) {
	area = length * width
	perimeter = (length + width) * 2
	return // 不需要明确指定返回值，默认返回 area, perimeter 的值
}
